<template>
     <!-- 父级进行  Provid进行通信 -->
     <Scene :salec="salec"
     @changePosi="changePosiFn"
     >
          <div class="dargcanvas" ref="dargRef" @drop="onDropfns" @dragover="onDropOverfns" @dragenter="onDragEnter"
              >

               <!-- 异步渲染 -->
               <div class="dropCon" @click="cavansClick" data-id="canvas">
                    <div class="dargs" v-for="item in Object.keys(stroe)" :key="item" :dataId="stroe[item].uid" :style="{
                         top: `${stroe[item].y}px`,
                         left: `${stroe[item].x}px`,
                         width: `${stroe[item].w}px`,
                         height: `${stroe[item].h}px`,
                         zIndex:`${stroe[item].zIndex}`
                    }" @contextmenu="onContextmenu"> 
                         <!-- 元组件 -->
                         <Metacomponents v-model="stroe[item]" :selectid="selectid" @onmousedown="onHandleDown">
                         </Metacomponents>
                    </div>
                    <!-- 右击菜单 -->
                    <MetaMenus :menusposi="menusposi" :ismenu="ismenu" @MenuClick="MenuClickfn"></MetaMenus>
                    <!-- 辅助线 -->
                    <AuxiliaryLine :line-l="lines.lineL" :line-r="lines.lineR" :left="lineleft" :right="lineright"
                         :line-t="lines.lineT" :top="linetop" :bottom="linebottom" :line-b="lines.lineB"></AuxiliaryLine>
               </div>
               <!-- 右击菜单 -- 右击事件需要选中才行 -->
          </div>
     </Scene>
</template>
<script lang="ts" setup>
//  该组件为核心组件--画布部分
import type { StroeType } from './type';
import { CanvasMateials } from './material/index';
import { onMounted, ref, reactive, defineAsyncComponent } from 'vue';
const Scene = defineAsyncComponent(() => import('./components/Scene.vue'));
const Metacomponents = defineAsyncComponent(() => import('./components/Metacomponents.vue'));
const MetaMenus = defineAsyncComponent(() => import('./components/MateMenu.vue'));
const AuxiliaryLine = defineAsyncComponent(() => import('./components/AuxiliaryLine.vue'));
import { toNum } from './utils';
const dargRef = ref<HTMLElement>();
const ikey = ref<Boolean>(false);
const salec = ref(1); // 最大为1.5  统一缩放标识
const itemsid = ref('');
const menusposi = ref({ x: 0, y: 0 });
const selectid = ref();
const boxlint = 2; // 临界点
// 辅助线
const lines = reactive({
     lineL: false,
     lineR: false,
     lineT: false,
     lineB: false
})
const lineleft = ref<string | number>(0);
const lineright = ref<string | number>(0);
const linetop = ref<string | number>(0);
const linebottom = ref<string | number>(0);
let pointerRef = ['tl', 'dl', 'tr', 'dr'];
let times = null;
// 监听状态变化
// 核心部分状态 
const stroe = ref<StroeType>({
     ...CanvasMateials
});
const target = ref<HTMLElement | undefined>();
const ismenu = ref(false);
const posi = reactive({
     x: 0,
     y: 0
})
const CanvasPost = reactive({x:0,y:0})
// 画布移动距离
const changePosiFn = ({x,y})=>{
     CanvasPost.x = x;
     CanvasPost.y = y
}


// 添加组件的入口方法
const onDropfns = (e) => {
     e.preventDefault();
     var data = JSON.parse(e.dataTransfer.getData("info"));
     let stroes = Object.keys(stroe.value).length as number;
     // 可以使用才能进行拖拽，或者这里后期可以加入权限------拓展用户对物料的使用权限 
     if (data.isdarg) {
          // 放置到指定的位置
          // （距离父级的位置-画布移动位置） - （自身1/2）/ 缩放
          // 初始化层级为当前的索引
          addStore({ ...data, zIndex:stroes,x: ((e.layerX-CanvasPost.x) - ((data.w / 2)) / salec.value), y:( e.layerY-CanvasPost.y) - ((data.h / 2) / salec.value) })
     }
}
// 拖放进入
const onDragEnter = (e) => {
     e.preventDefault();
}
// 允许放置
const onDropOverfns = (e) => {
     e.preventDefault();
}

// 菜单点击
const MenuClickfn = (e) => {
     console.log(e)
     if (e == 'remove') {
          delete stroe.value[selectid.value];
     } else if (e == 'copy') {
          // uid 暂时先写简单
          addStore({ ...stroe.value[selectid.value], uid: (Math.random() * 100) << 16 });
     }else if(e=='pre'){
          // 上一层调换位置
          changeLevelPosi(selectid.value,'pre');
     }else if(e=='next'){
          changeLevelPosi(selectid.value,'next');             
     }
     ismenu.value = false;
     selectid.value = '';
}
// 层级  
// 直接+2  因为层级不能等于 只能小于或者大于
const changeLevelPosi = (selectid,type)=>{ 
          if(type=='pre'){
               stroe.value[selectid]={...stroe.value[selectid],zIndex:stroe.value[selectid].zIndex+2}
          }else{
               stroe.value[selectid]={...stroe.value[selectid],zIndex:stroe.value[selectid].zIndex-2}
          }
       
}

// 点击画布
const cavansClick = (e) => {
     if (e.target.getAttribute('data-id') == 'canvas') {
          Object.values(stroe.value).forEach(item => {
               item.selectCon = false;
          })
          selectid.value = '';
          ismenu.value = false;
          clearlines();

     }
}

// 右击 
const onContextmenu = (e) => {
     e.preventDefault();
     let rect = dargRef.value?.getBoundingClientRect();
     menusposi.value.x = (e.pageX - rect.x) / salec.value;
     menusposi.value.y = (e.pageY - rect.y) / salec.value;
     ismenu.value = true;
}
// 初始化
onMounted(() => {
     document.addEventListener('mouseup', onHandleLeave)
})
// 移出--避免事件造成页面卡顿问题-清除所有状态
const onHandleLeave = () => {
     clearlines();
     ikey.value = false;
     itemsid.value = '';
     document.removeEventListener('mousemove', onHandleMove)
}
// 鼠标移动
// 1. 解决移动过快失去鼠标焦点问题，2. 新增等比缩放功能

// 通过这个函数进行辅助线的设置

const onHandleMove = (e) => {
     e.preventDefault();
     ismenu.value = false;
     let ids = itemsid.value;
     if (!times) {
          // 防抖
          times = setTimeout(() => {
               let targets = target.value?.getAttribute('data-set');
               // 位置移动与大小等比 统一计算
               let x = (e.screenX - posi.x) / salec.value;
               let y = (e.screenY - posi.y) / salec.value;
               if (targets && pointerRef.includes(targets)) {
                    // 改变大小  
                    changeSize(x, y, targets, ids);
               } else {
                    // 位置移动 
                    if (ikey.value && ids) {
                         // 缩放比例移动
                         stroe.value[ids].x = stroe.value[ids]?.x + x;
                         stroe.value[ids].y = stroe.value[ids]?.y + y;
                    }
               }
               auxiliaryLine(ids);
               posi.x = e.screenX;
               posi.y = e.screenY;
               clearTimeout(times);
               times = null;
          }, 10)
     }
}

// 辅助线
/**
 * 
 * @param items 单体物块
 */
const auxiliaryLine = (ids) => {
     clearlines();
     let selectCurrent = stroe.value[ids] as any;
     Object.values(stroe.value).forEach(item => {
          if (item.uid !== ids) {
               // 左-左
               if (Math.abs(item.x - selectCurrent.x) < boxlint) {
                    selectCurrent.x = item.x;
                    lineleft.value = item.x;
                    lines.lineL = true;
               }
               if (Math.abs((toNum(item.x) + toNum(item.w)) - (selectCurrent.x + selectCurrent.w)) < boxlint) {
                    lines.lineR = true;
                    lineright.value = toNum(item.x) + toNum(item.w);
               }
               if (Math.abs(item.y - selectCurrent.y) < boxlint) {
                    selectCurrent.y = item.y;
                    linetop.value = item.y;
                    lines.lineT = true;
               }
               if (Math.abs((toNum(item.y) + toNum(item.h)) - (selectCurrent.y + selectCurrent.h)) < boxlint) {

                    linebottom.value = toNum(item.y) + toNum(item.h);
                    lines.lineB = true;
               }
               // 右-右
               // 上-上
               // 下-下
               // 下-上
               // 上-下
               // 左-右
               // 右-左

          }

     })
}

// 清除样式
const clearlines = () => {
     lines.lineL = false;
     lines.lineR = false;
     lines.lineT = false;
     lines.lineB = false;
}


// 缩放
/**
 *  'tl':左上 'dl'：左下, 'tr'：右上, 'dr'：右下 
 * @param x 
 * @param y 
 * @param type 
 * @param uid 
 */
const changeSize = (x, y, type, uid) => {
     // 为了不让组件宽高不是很小--加入临界限制
     if (type == 'tr') {
          stroe.value[uid].w = stroe.value[uid]?.w + x;
          stroe.value[uid].h = stroe.value[uid]?.h - y;
          stroe.value[uid].y = stroe.value[uid]?.y + y;
     } else if (type == 'dr') {
          stroe.value[uid].w = stroe.value[uid]?.w + x;
          stroe.value[uid].h = stroe.value[uid]?.h + y;
     } else if (type == 'tl') {
          stroe.value[uid].w = stroe.value[uid]?.w - x;
          stroe.value[uid].x = stroe.value[uid]?.x + x;
          stroe.value[uid].h = stroe.value[uid]?.h - y;
          stroe.value[uid].y = stroe.value[uid]?.y + y;
     } else {
          stroe.value[uid].w = stroe.value[uid]?.w - x;
          stroe.value[uid].x = stroe.value[uid]?.x + x;
          stroe.value[uid].h = stroe.value[uid]?.h + y;
     }
}

// 鼠标按下
const onHandleDown = ({ e, info }) => {
     itemsid.value = info.uid;
     target.value = e.target;
     stroe.value[info.uid].selectCon = true;
     selectid.value = info.uid;
     document.addEventListener('mousemove', onHandleMove)
     ikey.value = true;
     ismenu.value = false;
     posi.x = e.screenX;
     posi.y = e.screenY;
}
// 状态操作事件----------------
const addStore = (e) => {
     stroe.value[e.uid] = e;
}
const removeStore = (e) => {
     delete stroe.value[e.uid];
}
// 获取JSON
const getJSON = () => {
     return stroe.value;
}

defineExpose({
     getJSON,
     addStore,
     removeStore
}) 
</script>
<style  scoped>
.dargcanvas {
     background-color: #fff;
     width: 100%;
     height: 100%;
     transform: scale(1);
   

}

.dropCon {
     width: 100%;
     height: 100%;
     position: relative;
}

.dargs {
     cursor: move;
     box-sizing: border-box;
     position: absolute;
     /* background-color: red; */

}
</style>